package com.apes.fn.fico.prepaid.service;

import com.apes.fn.fico.prepaid.model.PrepaidExpense;
import com.apes.fn.fico.prepaid.model.PrepaidExpenseItem;
import com.apes.fn.fico.prepaid.model.ShareDetail;
import com.apes.fn.fico.prepaid.repository.PrepaidExpenseRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.Model;
import com.apes.framework.jpa.generator.service.SequenceService;
import com.apes.framework.jpa.repository.CustomRepository;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.outbox.OutboxEventService;
import com.apes.framework.util.DateUtil;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @Title: PrepaidExpenseService
 * @Description: 待摊费用
 * @author: ZhengZeXian
 * @create: 2022/2/10 17:50
 */
@Service("prepaidExpenseService")
public class PrepaidExpenseService extends DomainService {

    @Autowired
    private PrepaidExpenseRepository prepaidExpenseRepository;
    @Autowired
    private OutboxEventService outboxEventService;
    @Autowired
    private SequenceService sequenceService;

    /***
     * 创建
     */
    public PrepaidExpense create(SimpleRequest request) {
        PrepaidExpense prepaidExpense = request.getO(PrepaidExpense.class);
        prepaidExpense.setState("create");
        return prepaidExpenseRepository.saveAndFlush(prepaidExpense);
    }

    /***
     * 更新
     */
    public PrepaidExpense update(SimpleRequest request) {
        isVaild(request, prepaidExpenseRepository);
        PrepaidExpense prepaidExpense = request.getO(PrepaidExpense.class);
        return prepaidExpenseRepository.saveAndFlush(prepaidExpense);
    }

    /***
     * 删除
     */
    public PrepaidExpense delete(SimpleRequest request) {
        isVaild(request, prepaidExpenseRepository);
        PrepaidExpense prepaidExpense = request.getO(PrepaidExpense.class);
        prepaidExpense.setState("delete");
        return prepaidExpenseRepository.saveAndFlush(prepaidExpense);
    }

    /**
     * 审核
     */
    public PrepaidExpense approve(SimpleRequest request) {
        isVaild(request, prepaidExpenseRepository);
        PrepaidExpense prepaidExpense = request.getO(PrepaidExpense.class);
        prepaidExpense.setState("approve");
        prepaidExpense.setApproveId(request.getPerson());
        prepaidExpense.setApproveDate(new Date());
        return prepaidExpenseRepository.saveAndFlush(prepaidExpense);
    }

    /**
     * 一次性分摊
     */
    public PrepaidExpense share(SimpleRequest request) {
        PrepaidExpense prepaidExpense = request.getO(PrepaidExpense.class);
        if (prepaidExpense.getStartShareDate() == null) prepaidExpense.setStartShareDate(new Date());
        //写入分摊总账
        writeShareDetail(0,prepaidExpense.getPrepaidExpenseItems(),request.getPerson(),false);
        prepaidExpense.setState("finish");
        prepaidExpense = prepaidExpenseRepository.saveAndFlush(prepaidExpense);
        prepaidExpense.getPrepaidExpenseItems().stream().forEach(peItem -> peItem.getShareDetails().stream().forEach(shareDetail ->
                outboxEventService.sendSaveEvent(shareDetail)));
        return prepaidExpense;
    }

    /**
     * 按月分摊
     */
    public PrepaidExpense shareMonth(SimpleRequest request) {
        PrepaidExpense prepaidExpense = request.getO(PrepaidExpense.class);
        if (prepaidExpense.getStartShareDate() == null) prepaidExpense.setStartShareDate(new Date());
        //写入分摊总账
//        writeShareDetail(1,prepaidExpense.getPrepaidExpenseItems(),request.getPerson(),false);
        prepaidExpense.setState(prepaidExpense.getPrepaidExpenseItems().stream().mapToDouble(item -> item.getSurplusPrepaidMonth()).sum() == 0 ? "finish" : "share");
        prepaidExpense = prepaidExpenseRepository.saveAndFlush(prepaidExpense);
        prepaidExpense.getPrepaidExpenseItems().stream().forEach(peItem -> peItem.getShareDetails().stream().forEach(shareDetail ->
                outboxEventService.sendSaveEvent(shareDetail)));
        return prepaidExpense;
    }

    /**
     * 写入分摊账目明细
     * @param type 0：一次性分摊  1：按月分摊
     * @param items 待摊费用明细
     * @param sharePerson 分摊人
     * @param isSystem 是否系统操作
     */
    public void writeShareDetail(int type, List<PrepaidExpenseItem> items,PartyRole sharePerson,Boolean isSystem){
        PartyRole company = items.stream().findFirst().get().getPrepaidExpense().getCompany();
        //记账日期 非系统定时任务操作取当前日期, 日结是每月一号执行,记账日期取上个月最后一天
        Date postDate = isSystem ? DateUtil.getMonthLastDay(DateUtil.add(new Date(), Calendar.MONTH, -1)) : new Date();
        items.forEach(item -> {
            if (item.getSurplusPrepaidMonth() == 0) return;
            ShareDetail detail = new ShareDetail();
            detail.setId(sequenceService.getId(ShareDetail.CONST_TABLE_NAME));
            detail.setPrepaidExpenseItem(item);
            detail.setShareDate(new Date());
            detail.setSharePerson(sharePerson);
            detail.setState("done");
            detail.setCompany(company);
            detail.setPostDate(postDate);

            //计算剩余待摊月份
            item.setSurplusPrepaidMonth(type == 0 ? 0 : item.getSurplusPrepaidMonth() - 1);
            //计算本次需要分摊的金额
            detail.setShareAmount(item.computeShareAmount(type));
            //计算已经分摊过的金额
            item.setAllocatedAmount(item.getShareDetails().stream().mapToDouble(share -> share.getShareAmount()).sum() + detail.getShareAmount());
            List<ShareDetail> shareDetails = item.getShareDetails();
            shareDetails.add(detail);
            item.setShareDetails(shareDetails);

        });
    }

    /**
     * 每月1号执行待摊费用单 分摊
     * @param request
     */
    public void timingShare(SimpleRequest request){
        List<PrepaidExpense> prepaidExpenseList = prepaidExpenseRepository.findAllByState("share");
        if(Objects.isNull(prepaidExpenseList)) return;
        //0002256 系统日结员
        PartyRole role = SpringManager.getBean(PartyRoleRepository.class).findOne("0002256");
        prepaidExpenseList.forEach(prepaidExpense -> {
            writeShareDetail(1,prepaidExpense.getPrepaidExpenseItems(),role,true);
            prepaidExpense = prepaidExpenseRepository.saveAndFlush(prepaidExpense);
            prepaidExpense.getPrepaidExpenseItems()
                    .forEach(peItem -> peItem.getShareDetails().stream()
                            .filter(shareDetail -> !Objects.isNull(shareDetail.getPostDate()))
                            //只推送当月生成的分摊费用单进事务发件箱
                            .filter(shareDetail -> DateUtil.format(DateUtil.getMonthLastDay(DateUtil.add(new Date(), Calendar.MONTH, -1)), "yyyy-MM-dd").equals(DateUtil.format(shareDetail.getPostDate(),"yyyy-MM-dd")))
                            .forEach(shareDetail -> outboxEventService.sendSaveEvent(shareDetail)));
        });
    }

    /***
     * 数据是否合法
     */
    private Model isVaild(SimpleRequest request, CustomRepository repository) {
        Model oldModel = (Model) repository.findOne((String) request.get("id"));
        if (oldModel == null) throw new RuntimeException("单据【" + request.get("id") + "】在系统中不存在。");
        if (oldModel.getVersion() != (int) request.get("version")) throw new RuntimeException("记录已更新或已删除，请重新提交！");
        return oldModel;
    }
}
